package com.alpha.core.entity;

import com.alpha.core.utils.CollectionUtil;
import com.alpha.core.utils.StringUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.MultiValueMap;

import java.util.*;

/**
 * 统一查询参数
 *
 * @author chenruwan
 * @since 2022-01-01
 */
@Data
@Slf4j
@Accessors(chain = true)
@NoArgsConstructor
@Schema(name = "查询参数")
public class AlphaQuery {
    public static final int DEFAULT_CURRENT = 1;
    public static final int DEFAULT_SIZE = 10;

    @Schema(description = "当前页")
    private Integer current;

    @Schema(description = "每页显示条数")
    private Integer size;

    @Schema(description = "自定义排序字段，例：(k1升序, k2降序, k3升序)的写法 orders=k1,-k2,k3 ")
    private List<String> orders = CollectionUtil.emptyList();

    @Schema(description = "智能查询参数")
    private String search;

    @Schema(description = "字段投影")
    private List<String> fields = CollectionUtil.emptyList();

    @Schema(description = "精确查询参数，例：(k1 = v1 and k2 = v2)的写法 equals=(k1,v1),(k2,v2)，也可以使用k1=v1&k2=v2")
    private String equals;

    @Schema(description = "模糊查询参数，例：(k1 like '%v1%' and k2 like '%v2%')的写法 likes=(k1,v1),(k2,v2), 也可以使用k1~=v1&k2~=v2")
    private String likes;

    @Schema(description = "范围查询参数，例：(k1 between l1 and r1)的写法 betweens=(k1,l1,r1), 可以使用k1>=l1&k1<=r1")
    private String betweens;

    @Schema(description = "in查询参数，例：(k1 in (v1, v2))的写法 ins=(k1,v1,v2), 也可以使用k1=v1&k1=v2")
    private String ins;

    @Schema(description = "分组聚合参数")
    private String groups;

    @Schema(hidden = true)
    private Map<String, List<String>> queryParams;

    public AlphaQuery(Integer current, Integer size) {
        this.current = current;
        this.size = size;
    }

    public <T> Page<T> page() {
        if (this.current == null && this.size == null) {
            return null;
        }
        if (this.current == null) {
            this.current = DEFAULT_CURRENT;
        }
        if (this.size == null) {
            this.size = DEFAULT_SIZE;
        }
        return new Page<>(this.current, this.size);
    }

    public AlphaQuery normalize(Map<String, String[]> params) {
        for (var entry : params.entrySet()) {
            for (var val : entry.getValue()) {
                normalize(entry.getKey(), val);
            }
        }
        return this;
    }

    public AlphaQuery normalize(MultiValueMap<String, String> params) {
        for (var entry : params.entrySet()) {
            for (var val : entry.getValue()) {
                normalize(entry.getKey(), val);
            }
        }
        return this;
    }

    private static Set<String> keywords = Set.of(
            "current", "size", "fields", "orders", "search", "equals", "likes", "betweens", "ins", "groups");

    private void normalize(String key, String value) {
        if (keywords.contains(key)) {
            return;
        }

        if (queryParams == null) {
            queryParams = new TreeMap<>();
        }

        queryParams.computeIfAbsent(key, k -> new ArrayList<>()).add(value);
    }

    private static final int MIN_PARAMETER_LENGTH = 3;

    public static List<String> parse(String parameter) {
        if (StringUtil.isBlank(parameter)) {
            return CollectionUtil.emptyList();
        }

        if (parameter.length() < MIN_PARAMETER_LENGTH
                || !parameter.startsWith(StringUtil.PARENTHESIS_START)
                || !parameter.endsWith(StringUtil.PARENTHESIS_END)) {
            log.warn("parameter is {}", parameter);
            return CollectionUtil.emptyList();
        }

        return Arrays.asList(parameter.substring(1, parameter.length() - 1).split("\\),\\("));
    }
}
